package de.westnordost.streetcomplete.data.osm;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Lineal;
import com.vividsolutions.jts.geom.Polygonal;
import com.vividsolutions.jts.linearref.LengthIndexedLine;
import java.util.ArrayList;
import java.util.List;
import de.westnordost.osmapi.map.data.LatLon;
import de.westnordost.streetcomplete.util.JTSConst;
/** Information on the geometry of a quest */
public class ElementGeometry
{
public LatLon center;
//* polygons are considered holes if they are defined clockwise */
public List<List<LatLon>> polygons = null;
public List<List<LatLon>> polylines = null;
public ElementGeometry(LatLon center)
{
this.center = center;
}
public ElementGeometry(List<List<LatLon>> polylines, List<List<LatLon>> polygons)
{
this.polygons = polygons;
this.polylines = polylines;
center = findCenterPoint();
}
public ElementGeometry(List<List<LatLon>> polylines, List<List<LatLon>> polygons, LatLon center)
{
this.polygons = polygons;
this.polylines = polylines;
this.center = center;
}
@Override public boolean equals(Object other)
{
if(other == null || !(other instanceof ElementGeometry)) return false;
ElementGeometry o = (ElementGeometry) other;
return
(polylines == null ? o.polylines == null : polylines.equals(o.polylines)) &&
(polygons == null ? o.polygons == null : polygons.equals(o.polygons));
}
private LatLon findCenterPoint()
{
try
{
Geometry geom = JTSConst.toGeometry(this);
if(!geom.isValid()) return null;
if(geom instanceof Polygonal)
{
return JTSConst.toLatLon(geom.getInteriorPoint());
}
else if(geom instanceof Lineal)
{
LengthIndexedLine lil = new LengthIndexedLine(geom);
return JTSConst.toLatLon(lil.extractPoint(geom.getLength() / 2.0));
}
}
catch (IllegalArgumentException e)
{
// unable to create proper geometry...
return null;
}
return null;
}
public static class Polygons { public List<List<LatLon>> outer, inner; }
public Polygons getPolygonsOrderedByOrientation()
{
Polygons result = new Polygons();
result.outer = new ArrayList<>();
result.inner = new ArrayList<>();
for(List<LatLon> polygon : polygons)
{
boolean isHole = ElementGeometry.isRingDefinedClockwise(polygon);
if(!isHole)
{
result.outer.add(polygon);
}
else
{
result.inner.add(polygon);
}
}
return result;
}
public static boolean isRingDefinedClockwise(List<LatLon> ring)
{
double sum = 0;
int len = ring.size();
for(int i = 0, j = len-1; i<len; j = i, ++i)
{
LatLon pos1 = ring.get(j);
LatLon pos2 = ring.get(i);
sum += pos1.getLongitude() * pos2.getLatitude() - pos2.getLongitude() * pos1.getLatitude();
}
return sum > 0;
}
}